<?php
declare (strict_types=1);

namespace app\admin\model;

use app\common\model\User as UserModel;
use app\admin\model\user\PointsLog as PointsLogModel;
use app\admin\model\user\BalanceLog as BalanceLogModel;
use app\common\model\user\Grade as GradeModel;
use app\admin\model\user\GradeLog as GradeLogModel;
use app\common\enum\Client as ClientEnum;
use app\common\enum\user\grade\log\ChangeType as ChangeTypeEnum;
use app\common\enum\user\balanceLog\Scene as SceneEnum;
use app\common\enum\user\pointsLog\Scene as PointsSceneEnum;

/**
 * 用户模型
 * Class User
 * @package app\admin\model
 */
class User extends UserModel
{
    // 充值类型枚举: 余额
    const RECHARGE_TYPE_BALANCE = 'balance';

    // 充值类型枚举: 积分
    const RECHARGE_TYPE_POINTS = 'points';

    /**
     * 隐藏的字段
     * @var array
     */
    protected $hidden = [
        'password',
    ];

    public function getAvatarAttr($value)
    {
        return get_file_url($value);
    }
    public function setAvatarAttr($value)
    {
        if(is_array($value)){
            $ids = [];
            foreach ($value as $key => $item) {
                $ids[] = $item['id'];
            }
            return count($ids)?implode(',', $ids):2;
        }else{
            return $value;
        }
    }

    /**
     * 获取当前用户总数
     * @param array $param 查询参数
     * @return int|string
     */
    public function getUserTotal(array $param = [])
    {
        // 检索查询条件
        $filter = $this->getUserTotalFilter($param);
        // 查询结果
        return $this->where($filter)
            ->count();
    }

    /**
     * 获取当前用户总数的查询条件
     * @param array $param
     * @return array
     */
    private function getUserTotalFilter(array $param = []): array
    {
        // 默认查询参数
        $params = $this->setQueryDefaultValue($param, [
            'date' => null,         // 注册日期 如: 2020-08-01
            'isConsume' => null,    // 是否已消费
        ]);
        // 检索查询条件
        $filter = [];
        if (!is_null($params['date'])) {
            $startTime = strtotime($params['date']);
            $filter[] = ['create_time', '>=', $startTime];
            $filter[] = ['create_time', '<', $startTime + 86400];
        }
        if (is_bool($params['isConsume'])) {
            $filter[] = ['pay_money', $params['isConsume'] ? '>' : '=', 0];
        }
        return $filter;
    }

    /**
     * 获取用户列表
     * @param array $param
     * @return \think\Paginator
     */
    public function getList(array $param = []): \think\Paginator
    {
        // 检索查询条件
        $filter = $this->getFilter($param);
        // 获取用户列表
        return $this->with(['grade'])
            ->where($filter)
            ->order(['create_time' => 'desc'])
            ->paginate(input('pageSize',10,'intval'))->each(function($item, $key){
                if($item['grade']){
                    $item['grade_name'] = $item['grade']['name'];
                }else{
                    $item['grade_name'] = '普通会员';
                }
                $item['platform'] = ClientEnum::getName($item['platform']);
                $item['gender_name'] = $this->gender[$item['gender']];
                return $item;
            });
    }

    /**
     * 获取查询条件
     * @param array $param
     * @return array
     */
    private function getFilter(array $param = []): array
    {
        // 默认查询条件
        $params = $this->setQueryDefaultValue($param, [
            'search' => '',    // 会员昵称
            'gradeId' => 0,    // 用户等级
            'betweenTime'=>'', // 起止时间
        ]);
        // 检索查询条件
        $filter = [];
        // 会员昵称
        !empty($params['search']) && $filter[] = ['nick_name|mobile', 'like', "%{$params['search']}%"];
        // 用户等级
        $params['gradeId'] > 0 && $filter[] = ['grade_id', '=', (int)$params['gradeId']];
        // 起止时间
        if (!empty($params['betweenTime'])) {
            $times = between_time($params['betweenTime']);
            $filter[] = ['create_time', '>=', $times['start_time']];
            $filter[] = ['create_time', '<', $times['end_time'] + 86400];
        }
        return $filter;
    }

    /**
     * 添加新记录
     * @param $data
     * @return bool
     */
    public function add($data): bool
    {
        $data['password'] = encryption_hash($data['password']);
        if(isset($data['avatar']['id'])){
            $data['avatar'] = $data['avatar']['id'];
        }
        return $this->save($data);
    }

    /**
     * 编辑记录
     * @param $data
     * @return bool
     */
    public function edit($data): bool
    {
        if(isset($data['password']) && !empty($data['password'])){
            $data['password'] = encryption_hash($data['password']);
        }
        if(isset($data['avatar']['id'])){
            $data['avatar'] = $data['avatar']['id'];
        }
        return $this->save($data) !== false;
    }

    /**
     * 用户充值
     * @param string $target 充值类型
     * @param array $data 表单数据
     * @return bool
     */
    public function recharge(string $target, array $data, string $adminUserName): bool
    {
        if ($target === self::RECHARGE_TYPE_BALANCE) {
            return $this->rechargeToBalance($adminUserName, $data);
        } elseif ($target === self::RECHARGE_TYPE_POINTS) {
            return $this->rechargeToPoints($adminUserName, $data);
        }
        return false;
    }

    /**
     * 用户充值：余额
     * @param string $adminUserName
     * @param array $data
     * @return bool
     */
    private function rechargeToBalance(string $adminUserName, array $data): bool
    {
        if (!isset($data['money']) || $data['money'] === '' || $data['money'] <= 0) {
            $this->error = '请输入正确的金额';
            return false;
        }
        // 判断充值方式，计算最终金额
        if ($data['mode'] === 'inc') {
            $diffMoney = $data['money'];
            $newMoney = $this['balance'] + $data['money'];
        } elseif ($data['mode'] === 'dec') {
            $diffMoney = -$data['money'];
            $newMoney = $this['balance'] - $data['money'];
        } else {
            $diffMoney = bcsub($data['money'], $this['balance']);
            $newMoney = $data['money'];
        }
        // 更新记录
        $this->transaction(function () use ($adminUserName, $data, $diffMoney, $newMoney) {
            // 更新账户余额
            static::setIncBalance((int)$this['user_id'], (float)$diffMoney);
            // 新增余额变动记录
            BalanceLogModel::add(SceneEnum::ADMIN, [
                'user_id' => $this['user_id'],
                'money' => (float)$diffMoney,
                'new_money' => (float)$newMoney,
                'remark' => $data['remark'],
            ], [$adminUserName]);
        });
        return true;
    }

    /**
     * 用户充值：积分
     * @param string $adminUserName
     * @param array $data
     * @return bool
     */
    private function rechargeToPoints(string $adminUserName, array $data): bool
    {
        if (!isset($data['value']) || $data['value'] === '' || $data['value'] <= 0) {
            $this->error = '请输入正确的积分数量';
            return false;
        }
        // 判断充值方式，计算最终积分
        if ($data['mode'] === 'inc') {
            $diffMoney = $data['value'];
            $newValue = $this['points'] + $data['value'];
        } elseif ($data['mode'] === 'dec') {
            $diffMoney = -$data['value'];
            $newValue = $this['points'] - $data['value'];
        } else {
            $diffMoney = $data['value'] - $this['points'];
            $newValue = $data['value'];
        }
        // 更新记录
        $this->transaction(function () use ($adminUserName, $data, $diffMoney, $newValue) {
            // 更新账户积分
            $this->setInc($this['user_id'], 'points', $diffMoney);
            // 新增积分变动记录
            PointsLogModel::add([
                'user_id' => $this['user_id'],
                'scene' => PointsSceneEnum::ADMIN,
                'value' => $diffMoney,
                'new_value' => $newValue,
                'describe' => "后台管理员 [{$adminUserName}] 操作",
                'remark' => $data['remark'],
            ]);
        });
        return true;
    }

    /**
     * 修改用户等级
     * @param array $data
     * @return mixed
     */
    public function updateGrade(array $data)
    {
        // 变更前的等级id
        $oldGradeId = $this['grade_id'];
        return $this->transaction(function () use ($oldGradeId, $data) {
            $grade = (new GradeModel)->where('grade_id', $data['grade_id'])->find();
            // 更新用户的等级
            $status = $this->save(['grade_id' => $data['grade_id']]);
            // 新增用户等级修改记录
            if ($status) {
                (new GradeLogModel)->save([
                    'user_id' => $this['user_id'],
                    'old_grade_id' => $oldGradeId,
                    'new_grade_id' => $data['grade_id'],
                    'change_type' => ChangeTypeEnum::ADMIN_USER,
                    'remark' => $data['remark']
                ]);
            }
            return $status !== false;
        });
    }
}
